import { ApiExtraModels, ApiOkResponse, ApiProperty, getSchemaPath } from '@nestjs/swagger'
import { applyDecorators, Type } from '@nestjs/common'
import { ApiResp } from './ApiResp'

const baseTypeNames = ['String', 'Number', 'Boolean']
// 用于解决ts不存储有关泛型或接口的元数据，导致swagger无法生成泛型的响应结果描述问题
// https://nest.nodejs.cn/openapi/operations#%E9%AB%98%E7%BA%A7%EF%BC%9A%E6%B3%9B%E5%9E%8B-apiresponse
// https://juejin.cn/post/7043781859569827848
/**
 * 用于解决ts不存储有关泛型或接口的元数据，导致swagger无法生成泛型的响应结果描述问题
 * @param model 泛型类型
 * @param isArray 是否数组结果
 * @param isPager 是否分页结果
 * @returns
 */
export const GenericApiResponse = <TModel extends Type<any>>(model?: TModel, isArray?: boolean, isPager?: boolean) => {
  let items = null
  if (model && baseTypeNames.includes(model.name)) {
    items = { type: model.name.toLocaleLowerCase() }
  } else {
    items = { $ref: getSchemaPath(model) }
  }
  let prop = null
  if (isArray && isPager) {
    prop = {
      type: 'object',
      properties: {
        list: {
          type: 'array',
          items,
          description: '分页结果',
        },
        total: {
          type: 'number',
          default: 0,
          description: '总记录数',
        },
        size: {
          type: 'number',
          default: 10,
          description: '每页记录数',
        },
        page: {
          type: 'number',
          default: 1,
          description: '页号',
        },
      },
    }
  } else if (isArray) {
    prop = {
      type: 'array',
      items,
    }
  } else if (model) {
    prop = items
  } else {
    prop = { type: 'null', default: null }
  }
  return applyDecorators(
    ApiExtraModels(ApiResp, model),
    ApiOkResponse({
      schema: {
        allOf: [
          { $ref: getSchemaPath(ApiResp) },
          {
            properties: {
              data: prop,
            },
          },
        ],
      },
    })
  )
}
